package StratelegoGame;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;

import javax.swing.JComponent;
import javax.swing.TransferHandler;

/**
 * This transfer handler allows the actual game piece to be 
 * dragged an dropped. To be completely honest, I'm not
 * quite sure how it works as I basically used most of the tutorial
 * on sun's website to create it.
 * @author Jace Ferguson
 * @filename GameBoard2DPieceTXHandler.java
 *
 */
public class GameBoard2DPieceTXHandler extends TransferHandler {
	/**
	 * Private class that creates an object that
	 * can be dragged and dropped. Drag and drop
	 * components must implement the trasnferable interface.
	 * @author Jace Ferguson
	 *
	 */
	class GameBoard2DPieceTransferable implements Transferable {
		GameBoard2DPiece piece;	//The piece to be transfered
		
		/**
		 * Constructor for the transferable saves the object inside the class
		 * @param piece	GameBoard2DPiece
		 */
		public GameBoard2DPieceTransferable(GameBoard2DPiece piece)
		{
			this.piece = piece;
		}
		
		/**
		 * When a drop spaces wants the data it calls this method
		 * which returns the object if the drop target knows
		 * how to handle the DataFlavor. In this case the 
		 * DataFlavor is a custom one call GameBoardPieceFlavor
		 * @return GameBoard2DPiece
		 */
		public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException
		{
			if(!isDataFlavorSupported(flavor))
			{
				throw new UnsupportedFlavorException(flavor);
			}
			return this.piece;
		}
		
		/**
		 * Returns a list of DataFlavors that the object will
		 * respond to. In this case we only need the transferable
		 * to respond to the custom GameBoardPieceFlavor.
		 * @return	DataFlavor[]
		 */
		public DataFlavor[] getTransferDataFlavors()
		{
			return new DataFlavor[] {GameBoardPieceFlavor};
		}
		
		/**
		 * Checks the target to see if its DataFlavor is
		 * support. 
		 * @return	boolean
		 */
		public boolean isDataFlavorSupported(DataFlavor flavor)
		{
			if(GameBoardPieceFlavor.equals(flavor))
			{
				return true;
			}
			return false;
		}

	}//End Private Class
	
	/*
	 * Members of the GameBoardPieceTXHandler class
	 */
	DataFlavor GameBoardPieceFlavor;
	String GameBoardPieceType = DataFlavor.javaJVMLocalObjectMimeType + ";class=StratelegoGame.GameBoard2DPiece";
	GameBoard2DPiece srcPiece;
	boolean shouldRemove;
	
	/**
	 * Create a transfer handler with the custom flavor.
	 */
	public GameBoard2DPieceTXHandler()
	{
		try{
			this.GameBoardPieceFlavor = new DataFlavor(this.GameBoardPieceType);
		}
		catch(ClassNotFoundException e)
		{
			/*
			 * Can't really throw a nice exception because
			 * the handler doesn't know about the application.
			 */
			System.err.println("Unable to create TX handler.");
		}
	}
	
	/**
	 * I'm pretty sure this is the method that checks
	 * to see if the target can handle an import on 
	 * the DataFlavor.
	 * @return	boolean
	 */
	public boolean canImport(JComponent c, DataFlavor[] flavors)
	{
		if(this.hasGameBoardPieceFlavor(flavors))
		{
			return true;
		}
		return false;
	}
	
	/**
	 * Creates the transferable object upon
	 * dragging of a DND capable component.
	 * @param	The component that was dragged
	 * @return	Transferable	A transferable object or
	 * 							null if an object couldn't be made.
	 */
	protected Transferable createTransferable(JComponent c)
	{
		if(c instanceof GameBoard2DPiece)
		{
			this.srcPiece = (GameBoard2DPiece)c;
			return new GameBoard2DPieceTransferable(this.srcPiece);
		}
		return null;
	}
	
	/**
	 * Not sure what this does although I believe it to 
	 * have something to do with removing the piece after
	 * it has been dragged an dropped. The other option was
	 * for the action to be COPY or MOVE_COPY. COPY
	 * did not remove the source object from the component.
	 */
	public int getSourceActions(JComponent c)
	{
		return MOVE;
	}
	
	
	/**
	 * Another method to check the DataFlavors.
	 * @param flavors	DataFlavor[]
	 * @return	boolean
	 */
	private boolean hasGameBoardPieceFlavor(DataFlavor[] flavors)
	{
		if(this.GameBoardPieceFlavor == null)
		{
			return false;
		}
		for(int i = 0; i < flavors.length; i++)
		{
			if(flavors[i].equals(this.GameBoardPieceFlavor))
			{
				return true;
			}
		}
		return false;
	}
	
	/**
	 * This method gets called after the drop has been made 
	 * and does the actual moving of objects.
	 */
	public boolean importData(JComponent c, Transferable t)
	{
		if(canImport(c, t.getTransferDataFlavors())){
			GameBoard2DSpace dropSpace = (GameBoard2DSpace)c;
			if(dropSpace.getPiece() != null && this.srcPiece == dropSpace.getPiece())
			{
				shouldRemove = false;
				return true;
			}
			try
			{
				if(this.hasGameBoardPieceFlavor(t.getTransferDataFlavors()))
				{
					GameBoard2DPiece txPiece = (GameBoard2DPiece) t.getTransferData(this.GameBoardPieceFlavor);
					if(dropSpace.getSpaceSetable()) //Only allow drops if the space allows it.
					{
						txPiece.getSpace().removePieceFromSpace();
						txPiece.getSpace().setSpaceSetable(true);
						dropSpace.addPieceToSpace(txPiece);
						dropSpace.setSpaceSetable(false);
						return true;
					}
					else
					{
						return false;
					}
				}
				else
				{
					return false;

				}
			}
			catch(UnsupportedFlavorException e)
			{
				System.err.println("Bad TX DataFlavor");
				return false;
			}
			catch(IOException e)
			{
				System.err.println("TX IO problem");
			}
		}
		return false;
	}
}


